﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;

namespace MyServer.Common
{
    /// <summary>
    /// 表示一个数据包
    /// </summary>

    public class DataPackage:IComparable<DataPackage>
    {

        #region ==========属性==========

        /// <summary>
        /// 表示数据包内数据的大小
        /// </summary>
        [DisplayName("数据大小")]
        [Description("表示数据包内数据的大小")]
        public long DataSize { get;private set; }
        /// <summary>
        /// 表示数据包的索引
        /// </summary>
        [DisplayName("索引")]
        [Description("表示数据包的在数据包列表中的索引")]
        public long ID { get; private set; }
        /// <summary>
        /// 表示数据包内的数据
        /// </summary>
        [DisplayName("数据")]
        [Description("表示数据包内包含的数据实体")]
        public byte[] Data { get;private set; }
        /// <summary>
        /// 表示数据包数据读取起始指针
        /// </summary>
        [DisplayName("数据起始指针")]
        [Description("表示数据包数据读取起始指针")]
        public long Offset { get; private set; }
        /// <summary>
        /// 数据包名称
        /// </summary>
        [DisplayName("名称")]
        [Description("表示数据包的名称")]
        public string PackageName { get; set; }
        /// <summary>
        /// 获取或设置与此数据包关联的其他数据
        /// </summary>
        public object Tag { get; set; }

        #endregion

        #region ========构造函数========
        /// <summary>
        /// 通过指定的数据与ID标识创建数据包实例
        /// </summary>
        /// <param name="Data">数据包包含的数据</param>
        /// <param name="ID">数据包的ID标识</param> 
        /// <remarks>
        /// 数据包一旦构造完毕就不支持更改，并且对于数据仅为引用，请自行手动释放数据
        /// </remarks>
        public DataPackage(byte[] Data, long ID,string Name)
        {
            this.Data = Data;
            this.DataSize = Data.Length;
            this.Offset = 0;
            this.ID = ID;
            this.PackageName = Name;
        }
        /// <summary>
        /// 通过指定参数创建数据包实例
        /// </summary>
        /// <param name="Data">数据包包含的数据</param>
        /// <param name="Offset">数据包数据的起始偏移</param>
        /// <param name="DataSize">数据包数据的大小</param>
        /// <param name="ID">数据包的ID标识</param>
        public DataPackage(byte[] Data, long Offset, long DataSize, long ID,string Name)
        {
            this.Data = Data;
            this.DataSize = DataSize;
            this.ID = ID;
            this.Offset = Offset;
            this.PackageName = Name;
        }
        #endregion

        #region========私有变量========

        private object lockobj = new object();

        #endregion

        #region ========公有函数========

        /// <summary>
        /// 将此数据包实例与指定实例进行ID比较并返回其相对值的指示
        /// </summary>
        /// <param name="other">要比较的实例</param>
        /// <returns></returns>
        public int CompareTo(DataPackage other)
        {
            return this.ID.CompareTo(other.ID);
        }

        /// <summary>
        /// 获取当前数据包中的数据
        /// </summary>
        /// <returns>获取到的数据</returns>
        public byte[] GetData()
        {
            lock(lockobj)
            {
                List<byte> lb = new List<byte>();
                for(long i= Offset;i< Offset+DataSize;i++)
                {
                    lb.Add(Data[i]);
                }
                return lb.ToArray();
            }
        }

        /// <summary>
        /// 将数据包及其中的数据转换为字节数组
        /// </summary>
        /// <returns></returns>
        public byte[] ToByte()
        {
            MemoryStream memstream=new MemoryStream();
            BinaryWriter writer = new BinaryWriter(memstream);
            writer.Write(this.ID);
            writer.Write(this.PackageName);
            byte[] DataBuffer = this.GetData();
            writer.Write(DataBuffer.Length);
            writer.Write(DataBuffer);
            long AddLen = memstream.Length % 16;
            writer.Write(new byte[AddLen]);
            writer.Flush();
            byte[] r = memstream.ToArray();
            writer.Close();
            return r;
        }

        private static object StaticLockObj=new object();
        /// <summary>
        /// 通过字节数组构造数据包实例
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static DataPackage FromByte(byte[] buffer)
        {
            lock (StaticLockObj)
            {
                MemoryStream memstream = new MemoryStream(buffer);
                BinaryReader reader = new BinaryReader(memstream);
                long id = reader.ReadInt64();
                string name = reader.ReadString();
                int dataLen = reader.ReadInt32();
                byte[] data = new Byte[dataLen];
                reader.Read(data, 0, dataLen);
                reader.Close();
                DataPackage pkg = new DataPackage(data, id, name);
                return pkg;
            }
        }

        #endregion

    }

}
